﻿using Microsoft.Extensions.DependencyInjection;
using RuoVea.ExCache;
using RuoVea.OmiApi.SystemApp.Service;
using System.Collections;
using System.Collections.Concurrent;
using System.Linq.Expressions;

using System.Reflection;
/// <summary>
/// SqlSugarFilter
/// </summary>
public class SqlSugarFilter
{
    /// <summary>
    /// ✔️ 业务数据过滤器- 配置用户机构集合过滤器- 配置用户机构（数据范围）过滤器 
    /// </summary>
    public static void SetOrgEntityFilter(IServiceCollection services, SqlSugarScopeProvider db)
    {
        if (services is null) return;
        ServiceProvider serviceProvider = services.BuildServiceProvider();
        if (serviceProvider is null) return;
        ICurrentUser currentUser = serviceProvider.GetService<ICurrentUser>();
        long userId = currentUser.UserId;
        if (userId <= 0) return;

        // 若仅本人数据，则直接返回
        var maxDataScope = SetDataScopeFilter(serviceProvider, db, userId);
        if (maxDataScope == 0 || maxDataScope == (int)DataScopeType.SELF) return;

        // 配置用户机构集合缓存
        var cacheKey = $"db:{db.CurrentConnectionConfig.ConfigId}:orgList:{userId}";

        var orgFilter = CacheFactery.Cache.Read<ConcurrentDictionary<Type, LambdaExpression>>(cacheKey);
        if (orgFilter == null)
        {
            // 获取用户最大数据范围，如果是全部数据，则跳过
            if (maxDataScope == (int)DataScopeType.ALL) return;

            // 获取用户所属机构，保证同一作用域
            var orgIds = serviceProvider.GetRequiredService<SysOrgService>().GetUserOrgIdList().GetAwaiter().GetResult();//获取当前用户机构Id集合
            if (orgIds == null || orgIds.Count == 0) return;

            // 获取业务实体数据表
            var entityTypes = FindEntityTypes<EntityBaseData>();
            if (!entityTypes.Any()) return;

            orgFilter = new ConcurrentDictionary<Type, LambdaExpression>();
            foreach (var entityType in entityTypes)
            {
                // 排除非当前数据库实体
                var tAtt = entityType.GetCustomAttribute<TenantAttribute>();
                if ((tAtt != null && db.CurrentConnectionConfig.ConfigId.ToString() != tAtt.configId.ToString()))
                    continue;

                var lambda = ParseLambda(new[] {
                        Expression.Parameter(entityType, "u") }, typeof(bool), $"@0.Contains(u.{nameof(EntityBaseData.CreateOrgId)}??{default(long)})", orgIds);

                db.QueryFilter.AddTableFilter(entityType, lambda);
                orgFilter.TryAdd(entityType, lambda);
            }
            CacheFactery.Cache.Write(cacheKey, orgFilter);
        }
        else
        {
            foreach (var filter in orgFilter)
                db.QueryFilter.AddTableFilter(filter.Key, filter.Value);
        }
    }

    /// <summary>
    /// 配置用户仅本人数据过滤器 没有继承 EntityBaseData 返回 ALL; 业务数据的过滤
    /// </summary>
    private static int SetDataScopeFilter(ServiceProvider services, SqlSugarScopeProvider db, long userId)
    {
        var maxDataScope = (int)DataScopeType.ALL;

        if (userId == 0) return maxDataScope;

        //获取用户最大数据范围-- - 仅本人数据
        maxDataScope = CacheFactery.Cache.Read<int>(CacheConst.KeyRoleMaxDataScope + userId);
        // 若为0则获取用户机构组织集合建立缓存
        if (maxDataScope == 0)
        {
            services.GetRequiredService<SysOrgService>().GetUserOrgIdList().GetAwaiter().GetResult();//里面执行设置缓存
            maxDataScope = CacheFactery.Cache.Read<int>(CacheConst.KeyRoleMaxDataScope + userId);
        }
        if (maxDataScope != (int)DataScopeType.SELF) return maxDataScope;

        // 配置用户数据范围缓存
        var cacheKey = $"db:{db.CurrentConnectionConfig.ConfigId}:dataScope:{userId}";
        var dataScopeFilter = CacheFactery.Cache.Read<ConcurrentDictionary<Type, LambdaExpression>>(cacheKey);
        if (dataScopeFilter == null)
        {
            // 获取业务实体数据表
            var entityTypes = FindEntityTypes<EntityBaseData>();
            if (!entityTypes.Any()) return maxDataScope;

            dataScopeFilter = new ConcurrentDictionary<Type, LambdaExpression>();
            foreach (var entityType in entityTypes)
            {
                // 排除非当前数据库实体
                var tAtt = entityType.GetCustomAttribute<TenantAttribute>();
                if ((tAtt != null && db.CurrentConnectionConfig.ConfigId.ToString() != tAtt.configId.ToString()))
                    continue;

                var lambda = ParseLambda(new[] {
                        Expression.Parameter(entityType, "u") }, typeof(bool), $"u.{nameof(EntityBaseData.Creator)}=@0", userId);

                db.QueryFilter.AddTableFilter(entityType, lambda);
                dataScopeFilter.TryAdd(entityType, lambda);
            }
            CacheFactery.Cache.Write(cacheKey, dataScopeFilter);
        }
        else
        {
            foreach (var filter in dataScopeFilter)
                db.QueryFilter.AddTableFilter(filter.Key, filter.Value);
        }
        return maxDataScope;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="parameters"></param>
    /// <param name="returnType"></param>
    /// <param name="expressionString"></param>
    /// <param name="values"></param>
    /// <returns></returns>
    private static LambdaExpression ParseLambda(ParameterExpression[] parameters, Type returnType, string expressionString, params object[] values)
    {
        var parameter = parameters[0];
        var body = Expression.Call(
            typeof(Expression),
            "Parse",
            new[] { returnType },
            Expression.Constant(expressionString));

        var lambda = Expression.Lambda(body, parameter);
        return lambda;
    }

    /// <summary>
    /// 查找所有继承自 EntityBaseData 的类型，并且具有 CreateOrgId 属性。
    /// </summary>
    /// <returns>符合条件的类型列表。</returns>
    private static List<Type> FindEntityTypes<T>()
    {
        var assemblies = AppDomain.CurrentDomain.GetAssemblies();
        var entityTypes = assemblies.SelectMany(assembly => assembly.GetTypes())
                                    .Where(type => !type.IsInterface && !type.IsAbstract && type.IsClass)
                                    .Where(type => type.IsSubclassOf(typeof(T)))
                                    //.Where(type => type.GetProperty(nameof(EntityBaseData.CreateOrgId)) != null)
                                    .ToList();
        return entityTypes;
    }

    /// <summary>
    /// ✔️ 配置自定义过滤器
    /// </summary>
    public static void SetCustomEntityFilter(IServiceCollection services, SqlSugarScopeProvider db, string mainConfigId = "0")
    {
        if (services is null) return;

        ServiceProvider serviceProvider = services.BuildServiceProvider();
        if (serviceProvider is null) return;

        ICurrentUser currentUser = serviceProvider.GetService<ICurrentUser>();
        long userId = currentUser.UserId;
        if (userId <= 0) return;

        // 配置自定义缓存
        var cacheKey = $"db:{db.CurrentConnectionConfig.ConfigId}:custom:{userId}";
        var tableFilterItemList = CacheFactery.Cache.Read<List<TableFilterItem<object>>>(cacheKey);
        if (tableFilterItemList == null)
        {
            // 获取自定义实体过滤器
            var entityFilterTypes = FindEntityTypes<IEntityFilter>();
            if (!entityFilterTypes.Any()) return;

            var tableFilterItems = new List<TableFilterItem<object>>();
            foreach (var entityFilter in entityFilterTypes)
            {
                var instance = Activator.CreateInstance(entityFilter);
                var entityFilterMethod = entityFilter.GetMethod("AddEntityFilter");
                var entityFilters = ((IList)entityFilterMethod?.Invoke(instance, null))?.Cast<object>();
                if (entityFilters == null) continue;

                foreach (var u in entityFilters)
                {
                    var tableFilterItem = (TableFilterItem<object>)u;
                    var entityType = tableFilterItem.GetType().GetProperty("type", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(tableFilterItem, null) as Type;
                    // 排除非当前数据库实体
                    var tAtt = entityType.GetCustomAttribute<TenantAttribute>();
                    if ((tAtt != null && db.CurrentConnectionConfig.ConfigId.ToString() != tAtt.configId.ToString()) ||
                        (tAtt == null && db.CurrentConnectionConfig.ConfigId.ToString() != mainConfigId))
                        continue;

                    tableFilterItems.Add(tableFilterItem);
                    db.QueryFilter.Add(tableFilterItem);
                }
            }
            CacheFactery.Cache.Write(cacheKey, tableFilterItems);
        }
        else
        {
            tableFilterItemList.ForEach(u =>
            {
                db.QueryFilter.Add(u);
            });
        }
    }
}